package sketch.specs;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.jdt.core.dom.CompilationUnit;

import randoop.util.Files;
import sketch.ast.ASTUtils;
import sketch.main.GeneratingTests;
import sketch.util.Checker;
import sketch.util.FileListing;
import sketch.util.Globals;
import sketch.util.SketchUtil;

public class SketchTestProcessorBatch {

	//it takes a dir as input, process all files in it, and return a set of compilation
	//unit after processing
	public final File dir;
	
	public SketchTestProcessorBatch(String dir) {
		this.dir = new File(dir);
		Checker.checkTrue(this.dir.isDirectory(), "The path: " + dir + " does not exist or is not a dir");
	}
	
	public SketchTestProcessor[] getSketchTestProcessors() {
		List<File> java_files = this.getAllJavaFiles();
		SketchTestProcessor[] processors = new SketchTestProcessor[java_files.size()];
		for(int i = 0; i < java_files.size(); i++) {
			processors[i] = new SketchTestProcessor(java_files.get(i).getAbsolutePath());
		}
		return processors;
	}
	
	/**
	 * It is the entry method. This method first transforms and expands each test sketch
	 * to produce a set of junit tests, then executes them reflectively online, and
	 * finally write the result to a given directory.
	 * */
	public void generateTestsFromSketches(String output_dir) {
		File f = new File(output_dir);
		if(!f.exists()) {
			f.mkdirs();
		} else {
			Checker.checkTrue(f.isDirectory(), "The: " + output_dir + " is not a directory.");
		}
		//First get a set of SketchTestProcessors
		SketchTestProcessor[] processors = this.getSketchTestProcessors();
		for(SketchTestProcessor processor : processors) {
			//expanding the notation, to create a compilation unit
			CompilationUnit unit = processor.getProcessedCompilationUnit();
			String packageName = unit.getPackage().getName().toString();
			String output_file_dir = output_dir + Globals.fileSep
			    + (packageName == null ? "" : SketchUtil.transClassNameDotToSlash(packageName));
			//symbolic execution here
			File output_dir_file = new File(output_file_dir);
			if(!output_dir_file.exists()) {
				output_dir_file.mkdirs();
			}
			
			//execute it reflectively
			GeneratingTests.genSymbolicValuesToOutputTests(unit, output_file_dir, processor.getFileNameWithoutSuffix(), packageName,
					null, null, null);
		}
	}
	
	/**
	 * The method is only for experiment purpose. it merely performs notation expansion.
	 * */
	public void generateTestsFromSketchesWithoutExecution(String output_dir) {
		File f = new File(output_dir);
		if(!f.exists()) {
			f.mkdirs();
		} else {
			Checker.checkTrue(f.isDirectory(), "The: " + output_dir + " is not a directory.");
		}
		//First get a set of SketchTestProcessors
		SketchTestProcessor[] processors = this.getSketchTestProcessors();
		for(SketchTestProcessor processor : processors) {
			System.out.println("Now processing: " + processor.sourcePath);
			//expanding the notation, to create a compilation unit
			CompilationUnit unit = processor.getProcessedCompilationUnit();
			String packageName = unit.getPackage().getName().toString();
			String output_file_dir = output_dir + Globals.fileSep
			    + (packageName == null ? "" : SketchUtil.transClassNameDotToSlash(packageName));
			//symbolic execution here
			File output_dir_file = new File(output_file_dir);
			if(!output_dir_file.exists()) {
				output_dir_file.mkdirs();
			}
			
			//no execution, just dump to the assigned places
			String outputFileAbsolutePath = output_file_dir + Globals.fileSep + processor.getFileNameWithoutSuffix() + ".java";
			ASTUtils.outputUnit(unit, outputFileAbsolutePath);
			System.out.println("  generated tests output to: " + outputFileAbsolutePath);
		}
	}
	
	private List<File> getAllJavaFiles() {
		List<File> allFiles = FileListing.getFiles(dir);
		List<File> javaFiles = new LinkedList<File>();
		for(File file : allFiles) {
			if(file.getName().endsWith(".java")) {
				javaFiles.add(file);
			}
		}
		return javaFiles;
	}
	
	public static void main(String[] args) {
		String src_dir = "./tests/sketch/issta11";
		SketchTestProcessorBatch batchProcessor = new SketchTestProcessorBatch(src_dir);
		
		String output_dir = "/scratch/tmp/issta11";
		batchProcessor.generateTestsFromSketches(output_dir);
	}
}